package demo.huangli.mydemosnew.logic_set_1.bolts;

import android.util.Log;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

import bolts.CancellationToken;
import bolts.CancellationTokenSource;
import bolts.Capture;
import bolts.Continuation;
import bolts.Task;
import bolts.TaskCompletionSource;

/**
 * Created by huangli on 17/12/29.
 */

public class BoltsHelper {

    public static String TAG = "BoltsHelper";

    public static CancellationTokenSource callCancleTask(){
        CancellationTokenSource cts = new CancellationTokenSource();
        Task<Integer> stringTask = getIntAsync(cts.getToken());
        return cts;
    }

    public static Task<Integer> getIntAsync(final CancellationToken ct){
        final TaskCompletionSource<Integer> tcs = new TaskCompletionSource<>();
        new Thread(){
            @Override
            public void run() {
                super.run();
                if (ct.isCancellationRequested()){
                    tcs.setCancelled();
                    return;
                }
                int result = 0;
                while (result < 100){
                    if (ct.isCancellationRequested()){
                        tcs.setCancelled();
                        return;
                    }
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    result++;
                    Log.i(TAG,"result "+result);
                }
                tcs.setResult(result);
            }
        }.start();
        return tcs.getTask();
    }

    public static void captureVariables(){
        final Capture<Integer> successfulSaveCount = new Capture<Integer>(0);

        int count = 0;

        Task.callInBackground(new Callable<Boolean>() {
            @Override
            public Boolean call() throws Exception {
                return true;
            }
        }).onSuccess(new Continuation<Boolean, Void>() {

            @Override
            public Void then(Task<Boolean> task) throws Exception {
                //count++; 这种情况必需声明count为final,但是声明成final后却不能改变它的值，这里就要使用Capture
                successfulSaveCount.set(successfulSaveCount.get()+1);
                return null;
            }
        });
    }

    public static void createTask(){
        TaskCompletionSource<String> successful = new TaskCompletionSource<>();
        successful.setResult("The good result.");
        successful.getTask().continueWith(new Continuation<String, Void>() {
            @Override
            public Void then(Task<String> task) throws Exception {
                Log.i(TAG,task.getResult());
                return null;
            }
        });
    }

    public static void login(){
        Task.callInBackground(new Callable<String>() {
            @Override
            public String call() throws Exception {
                Thread.sleep(1000);
//                if (1 < 10){
//                    throw new Exception("There was an error.");
//                }
                return "account : micaixiaoduanku password : 123456";
            }
        }).onSuccess(new Continuation<String, Object>() {
            @Override
            public Object then(Task<String> task) throws Exception {
                Log.i(TAG,"登录成功 "+task.getResult());
                return null;
            }
        },Task.UI_THREAD_EXECUTOR).continueWith(new Continuation<Object, Object>() {
            @Override
            public Object then(Task<Object> task) throws Exception {
                if (task.isFaulted()){
                    Log.i(TAG,"登录失败");
                    return null;
                }
                Log.i(TAG,"登录完成");
                return null;
            }
        },Task.UI_THREAD_EXECUTOR);
    }

    public static void errorHandling(){
        Task.call(new Callable<String>() {
            @Override
            public String call() throws Exception {
                Thread.sleep(2000);
                if (1 < 10){
                    Log.i(TAG,Thread.currentThread().getName() + " RuntimeException");
                    throw new RuntimeException("There was an error.");
                }
                return "hello bolts";
            }
        },Task.BACKGROUND_EXECUTOR).onSuccess(new Continuation<String, Void>() {
            @Override
            public Void then(Task<String> task) throws Exception {
                Log.i(TAG,Thread.currentThread().getName() + " onSuccess");
                return null;
            }
        },Task.UI_THREAD_EXECUTOR).continueWith(new Continuation<Void,Void>() {
            @Override
            public Void then(Task<Void> task) throws Exception {
                if (task.isFaulted()){
                    Log.i(TAG,Thread.currentThread().getName() + " error");
                    return null;
                }
                Log.i(TAG,Thread.currentThread().getName() + " done");
                return null;
            }
        },Task.UI_THREAD_EXECUTOR);

    }

    public static void callTasksInParallel(){
        final Executor PARALLEL_EXECUTOR = Executors.newCachedThreadPool();

        Task.call(new Callable<Void>() {
            @Override
            public Void call() throws Exception {
                for (int i = 0; i < 100; i++){
                    Log.i(TAG,Thread.currentThread().getName()+" i= "+i);
                }
                return null;
            }
        },PARALLEL_EXECUTOR);

        Task.call(new Callable<Void>() {
            @Override
            public Void call() throws Exception {
                for (int i = 0; i < 100; i++){
                    if (i % 2 == 1){
                        Log.i(TAG,Thread.currentThread().getName()+" i= "+i);
                    }
                }
                return null;
            }
        },PARALLEL_EXECUTOR);
    }

    public static void callTasksInSerial(){
        final Executor SERIAL_EXECUTOR = Executors.newSingleThreadExecutor();
        Task.call(new Callable<Void>() {
            @Override
            public Void call() throws Exception {
                for (int i = 0; i < 50; i++){
                    Log.i(TAG,Thread.currentThread().getName() + " i = " + i);
                }
                return null;
            }
        },SERIAL_EXECUTOR);
        Task.call(new Callable<Void>() {
            @Override
            public Void call() throws Exception {
                for (int i = 50; i < 100; i++){
                    Log.i(TAG,Thread.currentThread().getName() + " i = " + i);
                }
                return null;
            }
        },SERIAL_EXECUTOR);
    }

    public static void callGroupTasks(){
        Task.call(new Callable<Boolean>() {
            @Override
            public Boolean call() throws Exception {
                Log.i(TAG,Thread.currentThread().getName() + " calling");
                return true;
            }
        },Task.UI_THREAD_EXECUTOR).continueWith(new Continuation<Boolean, List<Task<Void>>>() {
            @Override
            public List<Task<Void>> then(Task<Boolean> task) throws Exception {
                Log.i(TAG,Thread.currentThread().getName() + " tasks start");
                List<Task<Void>> tasks = new ArrayList<Task<Void>>();
                tasks.add(asyncOperation1());
                tasks.add(asyncOperation2());
                Task.whenAll(tasks).waitForCompletion();
                Log.i(TAG,Thread.currentThread().getName() + " tasks end");
                return tasks;
            }
        },Task.BACKGROUND_EXECUTOR).continueWith(new Continuation<List<Task<Void>>, Void>() {
            @Override
            public Void then(Task<List<Task<Void>>> task) throws Exception {
                Log.i(TAG,Thread.currentThread().getName() + " done");
                return null;
            }
        },Task.UI_THREAD_EXECUTOR);
    }

    private static Task<Void> asyncOperation1(){
        return Task.callInBackground(new Callable<Void>() {
            @Override
            public Void call() throws Exception {
                Log.i(TAG,"asyncOperation1 start");
                try {
                    Thread.sleep(1000);
                }catch (Exception e){
                    Log.e(TAG,e.getMessage());
                }
                Log.i(TAG,"asyncOperation1 end");
                return null;
            }
        });
    }

    private static Task<Void> asyncOperation2(){
        return Task.callInBackground(new Callable<Void>() {
            @Override
            public Void call() throws Exception {
                Log.i(TAG,"asyncOperation2 start");
                try{
                    Thread.sleep(3000);
                }catch (Exception e){
                    Log.e(TAG,e.getMessage());
                }
                Log.i(TAG,"asyncOperation2 end");
                return null;
            }
        });
    }

    public static void callChainingTasks(){
        Task.call(new Callable<Boolean>() {
            @Override
            public Boolean call() throws Exception {
                Log.i(TAG,Thread.currentThread().getName() + " calling");
                Thread.sleep(2000);
                return true;
            }
        }, Task.UI_THREAD_EXECUTOR).continueWith(new Continuation<Boolean, String>() {
            @Override
            public String then(Task<Boolean> task) throws Exception {
                Log.i(TAG,Thread.currentThread().getName() + " onSuccess " + task.getResult());
                Thread.sleep(2000);
                return "hello bolts";
            }
        },Task.BACKGROUND_EXECUTOR).continueWith(new Continuation<String, Void>() {
            @Override
            public Void then(Task<String> task) throws Exception {
                Log.i(TAG,Thread.currentThread().getName() + " continueWith " + task.getResult());
                return null;
            }
        },Task.UI_THREAD_EXECUTOR);
    }

    public static void callOnBackGroundThread(){
        Task.callInBackground(new Callable<Boolean>() {
            @Override
            public Boolean call() throws Exception {
                Log.i(TAG,Thread.currentThread().getName() + " " + "call in background thread");
                return true;
            }
        });
    }

    public static void callOnCurThread(){
        Task.call(new Callable<Boolean>() {
            @Override
            public Boolean call() throws Exception {
                Log.i(TAG,Thread.currentThread().getName() + " " + "call in current thread");
                return true;
            }
        });
    }

    public static void callOnUiThread(){
        Task.call(new Callable<Boolean>() {
            @Override
            public Boolean call() throws Exception {
                Log.i(TAG,Thread.currentThread().getName() + " " + "call in main thread");
                return true;
            }
        },Task.UI_THREAD_EXECUTOR);
    }

    public static void callDelay(){
        Task.delay(2000).continueWith(new Continuation<Void, Void>() {
            @Override
            public Void then(Task<Void> task) throws Exception {
                Log.d(TAG,Thread.currentThread().getName() + " " + "call in main thread (after delay 2 seconds)");
                return null;
            }
        });
    }
}
